package com.orhanobut.wasp;
import com.android.volley.ExecutorDelivery;
import com.android.volley.Network;
import com.android.volley.RequestQueue;
import com.android.volley.ResponseDelivery;
import com.android.volley.toolbox.BasicNetwork;
import com.android.volley.toolbox.DiskBasedCache;
import com.orhanobut.wasp.http.Body;
import com.orhanobut.wasp.http.DELETE;
import com.orhanobut.wasp.http.GET;
import com.orhanobut.wasp.http.PATCH;
import com.orhanobut.wasp.http.POST;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.mockwebserver.MockResponse;
import com.squareup.okhttp.mockwebserver.MockWebServer;
import com.squareup.okhttp.mockwebserver.RecordedRequest;
import org.junit.Test;
import java.io.File;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import rx.Observable;
import rx.Observer;
import rx.schedulers.Schedulers;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
public class WaspTest extends BaseTestCase {
private static final long TIMEOUT = 4;
private final MockWebServer server = new MockWebServer();
private final RequestQueue requestQueue;
Executor executor = spy(new Executor() {
@Override
public void execute(Runnable command) {
command.run();
}
});
public WaspTest() throws Exception {
File cacheDir = new File(context.getCacheDir(), "volley");
Network network = new BasicNetwork(new OkHttpStack(new OkHttpClient()));
ResponseDelivery delivery = new ExecutorDelivery(executor);
requestQueue = new RequestQueue(new DiskBasedCache(cacheDir), network, 4, delivery);
requestQueue.start();
server.start();
}
static class User {
String name;
int no;
User(String name, int no) {
this.name = name;
this.no = no;
}
}
interface MyApiVoid {
@GET("/user") void getUser(Callback<User> callback);
}
@Test
public void voidCallbackGetForSuccess() throws Exception {
MockResponse response = new MockResponse()
.addHeader("Content-Type", "application/json; charset=utf-8")
.setBody("{\n" +
" \"no\": 123,\n" +
" \"name\": \"Hello\"\n" +
"}");
server.enqueue(response);
MyApiVoid myApi = new Wasp.Builder(context)
.setEndpoint(server.url("/v1").toString())
.setNetworkStack(VolleyNetworkStack.newInstance(requestQueue))
.build()
.create(MyApiVoid.class);
final CountDownLatch latch = new CountDownLatch(1);
myApi.getUser(new Callback<User>() {
@Override
public void onSuccess(Response response, User user) {
assertThat(response).isNotNull();
assertThat(user).isNotNull();
assertThat(user.name).isEqualTo("Hello");
assertThat(user.no).isEqualTo(123);
latch.countDown();
}
@Override
public void onError(WaspError error) {
fail(error.getErrorMessage());
}
});
RecordedRequest request = server.takeRequest();
assertThat(request.getPath()).isEqualTo("/v1/user");
assertThat(request.getMethod()).isEqualTo("GET");
assertTrue(latch.await(TIMEOUT, TimeUnit.SECONDS));
verify(executor).execute(any(Runnable.class));
verifyNoMoreInteractions(executor);
}
@Test
public void voidCallbackGetForFailure() throws Exception {
server.enqueue(new MockResponse().setStatus("404"));
MyApiVoid myApi = new Wasp.Builder(context)
.setEndpoint(server.url("/v1").toString())
.setNetworkStack(VolleyNetworkStack.newInstance(requestQueue))
.build()
.create(MyApiVoid.class);
final CountDownLatch latch = new CountDownLatch(1);
myApi.getUser(new Callback<User>() {
@Override
public void onSuccess(Response response, User user) {
fail("should fail");
}
@Override
public void onError(WaspError error) {
assertTrue(true);
assertThat(error).isNotNull();
assertThat(error.getResponse()).isNotNull();
// assertThat(error.getResponse().getStatusCode()).isEqualTo(404);
latch.countDown();
}
});
RecordedRequest request = server.takeRequest();
assertThat(request.getPath()).isEqualTo("/v1/user");
assertThat(request.getMethod()).isEqualTo("GET");
assertTrue(latch.await(TIMEOUT, TimeUnit.SECONDS));
verify(executor).execute(any(Runnable.class));
verifyNoMoreInteractions(executor);
}
interface MyApiWaspRequest {
@GET("/user") WaspRequest getUser(Callback<User> callback);
}
@Test
public void waspRequestGetForSuccess() throws Exception {
MockResponse response = new MockResponse()
.addHeader("Content-Type", "application/json; charset=utf-8")
.setBody("{\n" +
" \"no\": 123,\n" +
" \"name\": \"Hello\"\n" +
"}");
server.enqueue(response);
MyApiWaspRequest myApi = new Wasp.Builder(context)
.setEndpoint(server.url("/v1").toString())
.setNetworkStack(VolleyNetworkStack.newInstance(requestQueue))
.build()
.create(MyApiWaspRequest.class);
final CountDownLatch latch = new CountDownLatch(1);
WaspRequest waspRequest = myApi.getUser(new Callback<User>() {
@Override
public void onSuccess(Response response, User user) {
assertThat(response).isNotNull();
assertThat(user).isNotNull();
assertThat(user.name).isEqualTo("Hello");
assertThat(user.no).isEqualTo(123);
latch.countDown();
}
@Override
public void onError(WaspError error) {
fail(error.getErrorMessage());
}
});
assertThat(waspRequest).isNotNull();
RecordedRequest request = server.takeRequest();
assertThat(request.getPath()).isEqualTo("/v1/user");
assertTrue(latch.await(TIMEOUT, TimeUnit.SECONDS));
verify(executor).execute(any(Runnable.class));
verifyNoMoreInteractions(executor);
}
@Test
public void waspRequestGetWithCancel() throws Exception {
MockResponse response = new MockResponse()
.addHeader("Content-Type", "application/json; charset=utf-8")
.setBody("{\n" +
" \"no\": 123,\n" +
" \"name\": \"Hello\"\n" +
"}");
response.throttleBody(1024, 4, TimeUnit.SECONDS);
server.enqueue(response);
MyApiWaspRequest myApi = new Wasp.Builder(context)
.setEndpoint(server.url("/v1").toString())
.setNetworkStack(VolleyNetworkStack.newInstance(requestQueue))
.build()
.create(MyApiWaspRequest.class);
final CountDownLatch latch = new CountDownLatch(1);
WaspRequest waspRequest = myApi.getUser(new Callback<User>() {
@Override
public void onSuccess(Response response, User user) {
fail();
}
@Override
public void onError(WaspError error) {
fail(error.getErrorMessage());
}
});
assertThat(waspRequest).isNotNull();
//cancel request immediately
waspRequest.cancel();
RecordedRequest request = server.takeRequest();
assertThat(request.getPath()).isEqualTo("/v1/user");
assertFalse(latch.await(TIMEOUT, TimeUnit.SECONDS));
verify(executor).execute(any(Runnable.class));
verifyNoMoreInteractions(executor);
}
interface MyApiSync {
@GET("/user") User getUser();
}
@Test
public void syncGetForSuccess() throws Exception {
MockResponse response = new MockResponse()
.addHeader("Content-Type", "application/json; charset=utf-8")
.setBody("{\n" +
" \"no\": 123,\n" +
" \"name\": \"Hello\"\n" +
"}");
server.enqueue(response);
MyApiSync myApi = new Wasp.Builder(context)
.setEndpoint(server.url("/v1").toString())
.setNetworkStack(VolleyNetworkStack.newInstance(requestQueue))
.build()
.create(MyApiSync.class);
User user = myApi.getUser();
assertThat(user).isNotNull();
assertThat(user.name).isEqualTo("Hello");
RecordedRequest request = server.takeRequest();
assertThat(request.getPath()).isEqualTo("/v1/user");
verify(executor).execute(any(Runnable.class));
verifyNoMoreInteractions(executor);
}
@Test
public void syncGetForFailure() throws Exception {
server.enqueue(new MockResponse().setStatus("404"));
MyApiSync myApi = new Wasp.Builder(context)
.setEndpoint(server.url("/v1").toString())
.setNetworkStack(VolleyNetworkStack.newInstance(requestQueue))
.build()
.create(MyApiSync.class);
try {
myApi.getUser();
fail();
} catch (Exception e) {
//TODO add WaspError
// assertThat(e).isInstanceOf(WaspError.class);
assertTrue(e.getMessage(), true);
}
RecordedRequest request = server.takeRequest();
assertThat(request.getPath()).isEqualTo("/v1/user");
verify(executor).execute(any(Runnable.class));
verifyNoMoreInteractions(executor);
}
interface MyApiRx {
@GET("/user") Observable<User> getUser();
}
@Test
public void rxGetForSuccess() throws Exception {
MockResponse response = new MockResponse()
.addHeader("Content-Type", "application/json; charset=utf-8")
.setBody("{\n" +
" \"no\": 123,\n" +
" \"name\": \"Hello\"\n" +
"}");
server.enqueue(response);
MyApiRx myApi = new Wasp.Builder(context)
.setEndpoint(server.url("/v1").toString())
.setNetworkStack(VolleyNetworkStack.newInstance(requestQueue))
.build()
.create(MyApiRx.class);
Observable<User> observable = myApi.getUser();
assertThat(observable).isNotNull();
final CountDownLatch latch = new CountDownLatch(1);
observable
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.from(executor))
.subscribe(new Observer<User>() {
@Override
public void onCompleted() {
latch.countDown();
}
@Override
public void onError(Throwable e) {
fail("should fail");
}
@Override
public void onNext(User user) {
assertThat(user).isNotNull();
assertThat(user.name).isEqualTo("Hello");
}
});
RecordedRequest request = server.takeRequest();
assertThat(request.getPath()).isEqualTo("/v1/user");
assertTrue(latch.await(TIMEOUT, TimeUnit.SECONDS));
}
@Test
public void rxGetForFailure() throws Exception {
server.enqueue(new MockResponse().setStatus("404"));
MyApiRx myApi = new Wasp.Builder(context)
.setEndpoint(server.url("/v1").toString())
.setNetworkStack(VolleyNetworkStack.newInstance(requestQueue))
.build()
.create(MyApiRx.class);
Observable<User> observable = myApi.getUser();
assertThat(observable).isNotNull();
final CountDownLatch latch = new CountDownLatch(1);
observable
.subscribeOn(Schedulers.io())
.subscribe(new Observer<User>() {
@Override
public void onCompleted() {
fail();
}
@Override
public void onError(Throwable e) {
latch.countDown();
}
@Override
public void onNext(User user) {
fail("should fail");
}
});
RecordedRequest request = server.takeRequest();
assertThat(request.getPath()).isEqualTo("/v1/user");
assertTrue(latch.await(TIMEOUT, TimeUnit.SECONDS));
}
interface MyApiPost {
@POST("/user") User user(@Body User user);
}
@Test
public void syncPostForSuccess() throws Exception {
MockResponse response = new MockResponse()
.addHeader("Content-Type", "application/json; charset=utf-8")
.setBody("{\n" +
" \"no\": 123,\n" +
" \"name\": \"Hello\"\n" +
"}");
server.enqueue(response);
MyApiPost myApi = new Wasp.Builder(context)
.setEndpoint(server.url("/v1").toString())
.setNetworkStack(VolleyNetworkStack.newInstance(requestQueue))
.build()
.create(MyApiPost.class);
try {
User user = myApi.user(new User("Hello", 1));
assertThat(user).isNotNull();
} catch (Exception e) {
fail();
}
RecordedRequest request = server.takeRequest();
assertThat(request.getPath()).isEqualTo("/v1/user");
assertThat(request.getMethod()).isEqualTo("POST");
verify(executor).execute(any(Runnable.class));
verifyNoMoreInteractions(executor);
}
interface MyApiMethods {
@DELETE("/") Empty delete();
@PATCH("/") Empty patch(@Body User user);
}
static class Empty {
}
@Test
public void testDelete() throws Exception {
MockResponse response = new MockResponse()
.addHeader("Content-Type", "application/json; charset=utf-8")
.setBody("{}");
server.enqueue(response);
MyApiMethods myApi = new Wasp.Builder(context)
.setEndpoint(server.url("/v1").toString())
.setNetworkStack(VolleyNetworkStack.newInstance(requestQueue))
.build()
.create(MyApiMethods.class);
myApi.delete();
assertThat(server.takeRequest().getMethod()).isEqualTo("DELETE");
}
@Test
public void testPatch() throws Exception {
MockResponse response = new MockResponse()
.addHeader("Content-Type", "application/json; charset=utf-8")
.setBody("{}");
server.enqueue(response);
MyApiMethods myApi = new Wasp.Builder(context)
.setEndpoint(server.url("/v1").toString())
.setNetworkStack(VolleyNetworkStack.newInstance(requestQueue))
.build()
.create(MyApiMethods.class);
myApi.patch(new User("32424", 234));
assertThat(server.takeRequest().getMethod()).isEqualTo("PATCH");
}
//TODO validate arguments
//TODO validate url
//TODO validate headers
}